import useSystem from "@/store/useSystem"
import type { CalendarData, CalendarDate } from '@/types/common'

class Calendar {
    private Holidays
    private Works
    /**
     * 天干地支之天干速查表
     * @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
     */
    protected Gan = ["\u7532", "\u4e59", "\u4e19", "\u4e01", "\u620a", "\u5df1", "\u5e9a", "\u8f9b", "\u58ec", "\u7678"]

    /**
     * 天干地支之地支速查表
     * @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
     */
    protected Zhi = ["\u5b50", "\u4e11", "\u5bc5", "\u536f", "\u8fb0", "\u5df3", "\u5348", "\u672a", "\u7533", "\u9149", "\u620c", "\u4ea5"]

    /**
     * 天干地支之地支速查表<=>生肖
     * @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
     */
    protected Animals = ["\u9f20", "\u725b", "\u864e", "\u5154", "\u9f99", "\u86c7", "\u9a6c", "\u7f8a", "\u7334", "\u9e21", "\u72d7", "\u732a"]

    /**
     * 24节气速查表
     * @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
     */
    protected solarTerm = ["\u5c0f\u5bd2", "\u5927\u5bd2", "\u7acb\u6625", "\u96e8\u6c34", "\u60ca\u86f0", "\u6625\u5206", "\u6e05\u660e", "\u8c37\u96e8", "\u7acb\u590f", "\u5c0f\u6ee1", "\u8292\u79cd", "\u590f\u81f3", "\u5c0f\u6691", "\u5927\u6691", "\u7acb\u79cb", "\u5904\u6691", "\u767d\u9732", "\u79cb\u5206", "\u5bd2\u9732", "\u971c\u964d", "\u7acb\u51ac", "\u5c0f\u96ea", "\u5927\u96ea", "\u51ac\u81f3"]

    /**
     * 1900-2100各年的24节气日期速查表
     */
    protected sTermInfo = ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
        '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
        '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
        '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
        'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
        '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
        '97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
        '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
        '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
        '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
        '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
        '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
        '97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
        '9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
        '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
        '97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
        '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
        '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
        '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
        '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
        '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
        '97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
        '9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
        '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
        '97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
        '9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
        '7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
        '7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
        '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
        '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
        '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
        '97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
        '9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
        '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
        '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
        '977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
        '7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
        '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
        '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
        '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
        '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
        '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
        '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
        '977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
        '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
        '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
        '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
        '7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
        '7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
        '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
        '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
        '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
        '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
        '7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
        '7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
        '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
        '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
        '7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
        '665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
        '7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
        '7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
        '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722']

    /**
     * 数字转中文速查表
     * @trans ['日','一','二','三','四','五','六','七','八','九','十']
     */
    protected nStr1 = ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341"]

    /**
     * 日期转农历称呼速查表
     * @trans ['初','十','廿','卅']
     */
    protected nStr2 = ["\u521d", "\u5341", "\u5eff", "\u5345"]

    /**
     * 月份转农历称呼速查表
     * @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
     */
    protected nStr3 = ["\u6b63", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u51ac", "\u814a"]

    /**
     * 公历节日
     **/
    protected sFtv = [
        "0101 元旦", "0214 情人节", "0308 妇女节", "0312 植树节", "0315 消费者权益日", "0401 愚人节", "0501 劳动节",
        "0504 青年节", "0512 护士节", "0601 儿童节", "0701 建党节", "0801 建军节", "0910 教师节", "0928 孔子诞辰",
        "1001 国庆节", "1006 老人节", "1024 联合国日", "1224 平安夜", "1225 圣诞节", "1101 万圣节"
    ]

    /**
     * 农历节日
     **/
    protected lFtv = ["0101 春节", "0115 元宵节", "0505 端午节", "0707 七夕情人节", "0715 中元节", "0815 中秋节", "0909 重阳节", "1208 腊八节", "1224 小年"]

    /**
     *  公历月份中文表
     **/
    protected monthStr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']

    /**
     * 公历每个月份的天数普通表
     * @Array Of Property
     * @return Number
     */
    protected solarMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    /**
     * 农历1900-2100的润大小信息表
     * @Array Of Property
     * @return Hex
     */
    protected lunarInfo = [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,//1900-1909
        0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,//1910-1919
        0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,//1920-1929
        0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,//1930-1939
        0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,//1940-1949
        0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0,//1950-1959
        0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,//1960-1969
        0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6,//1970-1979
        0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,//1980-1989
        0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,//1990-1999
        0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,//2000-2009
        0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,//2010-2019
        0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,//2020-2029
        0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,//2030-2039
        0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,//2040-2049
        /**Add By JJonline@JJonline.Cn**/
        0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0,//2050-2059
        0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4,//2060-2069
        0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0,//2070-2079
        0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160,//2080-2089
        0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252,//2090-2099
        0x0d520]//2100
    /** 
     * 按星期过的节日信息
     */
    protected weekDays: Record<string, string> = {
        '060300': "父亲节",
        '050200': "母亲节",
    }

    // 格式化日期：如果日期格式错误则更正到正确日期，不能更正的抛出异常
    private forDays(date: CalendarDate): CalendarDate {
        if (date.y < 1900 || date.y > 2100 || date.m < 1 || date.m > 12 || date.d < 1 || date.d > 31) {
            const system = useSystem()
            const d = new Date(system.time)
            date.y = d.getFullYear()
            date.m = d.getMonth() + 1
            date.d = d.getDate()
        }
        const day = this.solarMonthDays(date)
        date.d = date.d > day ? day : date.d
        return date
    }

    // 获取公历月份天数
    private solarMonthDays(date: CalendarDate): number {
        if (date.m == 2) return (date.y % 4 == 0 && date.y % 100 != 0 || date.y % 400 == 0) ? 29 : 28
        return this.solarMonth[date.m - 1]
    }

    // 获取当月前面需补齐的数组
    private beforDays(date: CalendarDate): Date[] {
        //当月1号星期数 - 1，如果星期数为0则返回6
        let w = this.solarWeek({ y: date.y, m: date.m, d: 1 })
        w = w ? w - 1 : 6
        let arr = []
        const firstDay = new Date(date.y, date.m - 1, 1)
        for (let i = 1; i <= w; i++) {
            arr.unshift(new Date(firstDay.setDate(firstDay.getDate() - 1)))
        }
        return arr
    }

    // 返回上月日期+当月日期数组
    private arrDays(date: CalendarDate): Date[] {
        let arr = this.beforDays(date)
        // 获取当月天数
        let dd = this.solarMonthDays(date)
        for (let i = 1; i <= dd; i++) {
            arr.push(new Date(date.y, date.m - 1, i))
        }
        return arr
    }

    // 返回上月+当月+下月日期数组
    private afterDays(date: CalendarDate): Date[] {
        let arr = this.arrDays(date)
        const d = new Date(arr[arr.length - 1])
        const l = arr.length
        for (let i = 1; i <= 42 - l; i++) {
            arr.push(new Date(d.setDate(d.getDate() + 1)))
        }
        return arr
    }

    // 获取公历某一天是星期几
    public solarWeek(date: CalendarDate): number {
        const d = new Date(date.y, date.m - 1, date.d)
        return d.getDay()
    }

    // 查询一个公历日期是否法定节假日
    public getHolidays(date: Date): boolean {
        const y = date.getFullYear(),
            m = date.getMonth() + 1,
            d = date.getDate()
        const mm = String(m).padStart(2, '0'),
            dd = String(d).padStart(2, '0')
        return this.Holidays.includes([y, mm, dd].join(""))
    }

    // 查询一个公历日期是否法定节假日调休上班日
    public getWorks(date: Date): boolean {
        const y = date.getFullYear(),
            m = date.getMonth() + 1,
            d = date.getDate()
        const mm = String(m).padStart(2, '0'),
            dd = String(d).padStart(2, '0')
        return this.Works.includes([y, mm, dd].join(""))
    }

    // 查询公历日期节日
    public getSolarDay(m: number, d: number): string | false {
        let solarDay = ''
        for (let i = 0; i < this.sFtv.length; i++) {
            if (parseInt(this.sFtv[i].slice(0, 2)) == m && parseInt(this.sFtv[i].slice(2, 4)) == d) {
                solarDay = this.sFtv[i].slice(5)
            }
        }
        return solarDay ? solarDay : false
    }

    // 返回公历日期所属星座
    public toAstro(date: Date): string {
        let s = "\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf"
        let arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
        const m = date.getMonth() + 1
        const d = date.getDate()
        let i = m * 2 - (d < arr[m - 1] ? 2 : 0)
        return s.slice(i, i + 2) + "\u5ea7"
    }

    // 获取公历年第n个节气日期
    public getTerm(y: number, n: number): number {
        let _table = this.sTermInfo[y - 1900]
        let _info = [
            parseInt('0x' + _table.slice(0, 5)).toString(),
            parseInt('0x' + _table.slice(5, 10)).toString(),
            parseInt('0x' + _table.slice(10, 15)).toString(),
            parseInt('0x' + _table.slice(15, 20)).toString(),
            parseInt('0x' + _table.slice(20, 25)).toString(),
            parseInt('0x' + _table.slice(25)).toString()
        ]
        let d = [
            _info[0].slice(0, 1),
            _info[0].slice(1, 3),
            _info[0].slice(3, 4),
            _info[0].slice(4, 6),

            _info[1].slice(0, 1),
            _info[1].slice(1, 3),
            _info[1].slice(3, 4),
            _info[1].slice(4, 6),

            _info[2].slice(0, 1),
            _info[2].slice(1, 3),
            _info[2].slice(3, 4),
            _info[2].slice(4, 6),

            _info[3].slice(0, 1),
            _info[3].slice(1, 3),
            _info[3].slice(3, 4),
            _info[3].slice(4, 6),

            _info[4].slice(0, 1),
            _info[4].slice(1, 3),
            _info[4].slice(3, 4),
            _info[4].slice(4, 6),

            _info[5].slice(0, 1),
            _info[5].slice(1, 3),
            _info[5].slice(3, 4),
            _info[5].slice(4, 6),
        ]
        return parseInt(d[n - 1])
    }

    // 根据公历日期返回农历日期
    public getLunars(date: Date): {
        nYear: string
        nMonth: string
        nDay: string
        animals: string
        solarTerm: string
        holidays?: string[]
        isHoliday?: boolean
        isWork?: boolean
    } {
        let i, leap = 0, temp = 0
        let offset = (Date.UTC(date.getFullYear(),
            date.getMonth(), date.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
        for (i = 1900; i < 2101 && offset > 0; i++) {
            temp = this.lYearDays(i)
            offset -= temp
        }
        if (offset < 0) {
            offset += temp
            i--
        }
        // 获取闰月
        let year = i
        leap = this.leapMonth(i)
        let isLeap = false
        // 校验闰月
        for (i = 1; i < 13 && offset > 0; i++) {
            if (leap > 0 && i == leap + 1 && !isLeap) {
                --i
                isLeap = true
                temp = this.leapDays(year) // 闰月天数
            } else {
                temp = this.monthDays(year, i) // 普通月天数
            }
            if (isLeap && i == leap + 1) isLeap = false
            offset -= temp
        }
        if (offset == 0 && leap > 0 && i == leap + 1) {
            if (isLeap) {
                isLeap = false
            } else {
                isLeap = true
                --i
            }
        }
        if (offset < 0) {
            offset += temp
            --i
        }
        // 农历月
        let month: string = isLeap ? "0" + i : i + ""
        // 农历日
        let day = ++offset
        const y = date.getFullYear(),
            m = date.getMonth() + 1,
            d = date.getDate(),
            firstNode = this.getTerm(y, m * 2 - 1),
            secondNode = this.getTerm(y, m * 2)
        let term = ""
        if (firstNode == d) term = this.solarTerm[m * 2 - 2]
        if (secondNode == d) term = this.solarTerm[m * 2 - 1]
        const holidays: string[] = []
        const wh = this.getWeekDays(date)
        const gh = this.getSolarDay(m, d)
        const nh = this.getlunarDay(year, month, day)
        nh && holidays.push(nh)
        gh && holidays.push(gh)
        wh && holidays.push(wh)

        return {
            nYear: this.toGanZhiYear(year),
            nMonth: this.toChinaMonth(month),
            nDay: this.toChinaDay(day),
            animals: this.Animals[(year - 4) % 12], // 属相
            solarTerm: term, // 24节气
            holidays: holidays, // 假期
            isHoliday: this.getHolidays(date), // 节假日
            isWork: this.getWorks(date),  // 调休日
        }
    }

    // 返回农历月份通俗表示法
    public toChinaMonth(m: string): string {
        let r = m.slice(0, 1) == '0'
        const month = parseInt(m)
        return r ? ('\u95f0' + this.nStr3[month - 1] + '\u6708') : (this.nStr3[month - 1] + '\u6708') // 加上"月"字
    }

    // 返回农历日期通俗表示法
    public toChinaDay(d: number): string {
        let str = d == 10 ? this.nStr2[0] : this.nStr2[Math.floor(d / 10)]
        return str + (d % 10 ? this.nStr1[d % 10] : this.nStr1[10])
    }

    // 取农历非闰月的总天数
    public monthDays(y: number, m: number): 30 | 29 {
        return (this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29
    }

    // 通过农历日期获取农历节日
    public getlunarDay(y: number, m: string, d: number): false | string {
        if (m.slice(0, 1) == '0') return false //如果是闰月则没有节日
        const m2 = parseInt(m)
        let lunarDay = ''
        for (let i = 0; i < this.lFtv.length; i++) {
            if (parseInt(this.lFtv[i].slice(0, 2)) == m2 && parseInt(this.lFtv[i].slice(2, 4)) == d) {
                lunarDay = this.lFtv[i].slice(5)
            }
        }
        // 判断是否为除夕
        if (m2 == 12 && this.monthDays(y, m2) == d) lunarDay = '除夕'
        return lunarDay ? lunarDay : false
    }

    // 返回农历年闰月，没有闰月则返回0
    public leapMonth(y: number): number {
        return this.lunarInfo[y - 1900] & 0xf
    }

    // 返回农历年闰月的天数，没有闰月则返回0
    public leapDays(y: number): 30 | 0 | 29 {
        return this.leapMonth(y) ? ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29) : 0
    }

    // 回农历一年的天数
    public lYearDays(y: number): number {
        let i, sum = 348
        for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
        return (sum + this.leapDays(y))
    }

    // 返回农历年份干支纪年
    public toGanZhiYear(y: number): string {
        let g = (y - 3) % 10
        let z = (y - 3) % 12
        g = (g == 0) ? 10 : g
        z = (z == 0) ? 12 : z
        return this.Gan[g - 1] + this.Zhi[z - 1]
    }

    // 根据偏移量返回干支
    public toGanZhi(offset: number): string {
        return this.Gan[offset % 10] + this.Zhi[offset % 12]
    }

    // 按星期过的节日
    public getWeekDays(date: Date): string | false {
        const w = date.getDay()
        for (const key in this.weekDays) {
            let month = parseInt(key.slice(0, 2)),
                node = parseInt(key.slice(2, 4)),
                week = parseInt(key.slice(4))
            if (w == week && date.getMonth() + 1 == month && Math.ceil(date.getDate() / 7) == node) return this.weekDays[key]
        }
        return false
    }

    // 根据日期获取当月日期数组信息
    public getCalendars(date: CalendarDate): CalendarData[] {
        // 格式化日期，防止传入不正确的日期
        date = this.forDays(date)
        let arr: CalendarData[] = []
        this.afterDays(date).forEach(dateArr => {
            const nDays = this.getLunars(dateArr)
            // console.log(nDays)
            arr.push({
                date: dateArr,
                year: dateArr.getFullYear(),
                month: dateArr.getMonth() + 1,
                day: dateArr.getDate(),
                week: dateArr.getDay(),
                star: this.toAstro(dateArr),
                animals: nDays.animals,
                nYear: nDays.nYear,
                nMonth: nDays.nMonth,
                nDay: nDays.nDay,
                solarTerm: nDays.solarTerm,
                holidays: nDays.holidays,
                isHoliday: nDays.isHoliday,
                isWork: nDays.isWork,
                isToday: dateArr.getFullYear() == date.y && dateArr.getMonth() + 1 == date.m && dateArr.getDate() == date.d
            })
        })

        return arr
    }

    constructor(opt: HolidayResponse) {
        this.Holidays = opt.holidays
        this.Works = opt.works
    }
}

export default Calendar